#include "game_debug_ui.h"
#include "game_debug.h"
layout_element BeginElementRectangle(layout *Layout, v2 *Dim) {
    layout_element Element = {};
    Element.Layout = Layout;
    Element.Dim = Dim;
    return Element;
}
//  void MakeElementSizable(layout_element *Element) { Element->Size = Element->Dim; }
void DefaultInteraction(layout_element *Element, debug_interaction Interaction) {
    Element->Interaction = Interaction;
}
void AdvanceElement(layout *Layout, rectangle2 ElementRect) {
    Layout->NextYDelta = Minimum(Layout->NextYDelta, GetMinCorner(ElementRect).y - Layout->At.y);
    if (Layout->NoLineFeed) {
        Layout->At.x = GetMaxCorner(ElementRect).x + Layout->SpacingX;
    } else {
        real32 SpacingY = Layout->SpacingY;
        Layout->At.y += Layout->NextYDelta - SpacingY;
        Layout->LineInitialized = false;
    }
}

void EndElement(layout_element *Element) {
    layout *Layout = Element->Layout;
    debug_state *DebugState = Layout->DebugState;

    if (!Layout->LineInitialized) {
        Layout->At.x = Layout->BaseCorner.x + Layout->Depth * 2.0f * Layout->LineAdvance;
        Layout->LineInitialized = true;
        Layout->NextYDelta = 0.0f;
    }

    real32 SizeHandlePixels = 4.0f;
    v2 Frame = {0, 0};
    if (Element->Size) {
        Frame.x = SizeHandlePixels;
        Frame.y = SizeHandlePixels;
    }
    v2 TotalDim = *Element->Dim + 2.0f * Frame;
    v2 TotalMinCorner = {Layout->At.x,  //
                         Layout->At.y - TotalDim.y};
    v2 TotalMaxCorner = TotalMinCorner + TotalDim;
    v2 InteriorMinCorner = TotalMinCorner + Frame;
    v2 InteriorMaxCorner = InteriorMinCorner + *Element->Dim;
    rectangle2 TotalBounds = RectMinMax(TotalMinCorner, TotalMaxCorner);
    Element->Bounds = RectMinMax(InteriorMinCorner, InteriorMaxCorner);

    v2 SizeP = v2{GetMaxCorner(Element->Bounds).x, GetMinCorner(Element->Bounds).y};
    (void)SizeP;
    if (Element->Interaction.Type && IsInRectangle(Element->Bounds, Layout->MouseP)) {
        DebugState->NextHotInteraction = Element->Interaction;
    }

    if (Element->Size) {
        PushRect(&DebugState->RenderGroup, &DebugState->BackingTransform,
                 RectMinMax(v2{TotalMinCorner.x, InteriorMinCorner.y},
                            v2{InteriorMinCorner.x, InteriorMaxCorner.y}),
                 0.0f, v4{0, 0, 0, 1});
        PushRect(&DebugState->RenderGroup, &DebugState->BackingTransform,
                 RectMinMax(v2{InteriorMaxCorner.x, InteriorMinCorner.y},
                            v2{TotalMaxCorner.x, InteriorMaxCorner.y}),
                 0.0f, v4{0, 0, 0, 1});
        PushRect(&DebugState->RenderGroup, &DebugState->BackingTransform,
                 RectMinMax(V2(InteriorMinCorner.x, TotalMinCorner.y),
                            V2(InteriorMaxCorner.x, InteriorMinCorner.y)),
                 0.0f, V4(0, 0, 0, 1));
        PushRect(&DebugState->RenderGroup, &DebugState->BackingTransform,
                 RectMinMax(v2{InteriorMinCorner.x, TotalMaxCorner.y},
                            v2{InteriorMaxCorner.x, InteriorMaxCorner.y}),
                 0.0f, v4{0, 0, 0, 1});

        debug_interaction SizeInteraction = {};
        SizeInteraction.Type = DebugInteraction_Resize;
        SizeInteraction.P = Element->Size;
        rectangle2 SizeBox = AddRadiusTo(RectMinMax(v2{InteriorMaxCorner.x, TotalMinCorner.y},
                                                    v2{TotalMaxCorner.x, InteriorMinCorner.y}),
                                         v2{4, 4});

        PushRect(&DebugState->RenderGroup, &DebugState->BackingTransform, SizeBox, 0.0f,
                 InteractionsIsHot(DebugState, SizeInteraction) ?  //
                     v4{1, 0, 0, 1}
                                                                : v4{0.25, 0.25, 0.25, 1});

        if (IsInRectangle(SizeBox, Layout->MouseP)) {
            DebugState->NextHotInteraction = SizeInteraction;
        }
    }
    AdvanceElement(Layout, TotalBounds);
}

v2 BasicTextElement(layout *Layout, const char *Text, debug_interaction ItemInteraction,
                    v4 ItemColor, v4 HotColor, real32 Border, v4 BackdropColor) {
    debug_state *DebugState = Layout->DebugState;
    rectangle2 TextBounds = DEBUGGetTextSize(Layout->DebugState, Text);
    v2 Dim = {GetDim(TextBounds).x + 2.0f * Border, Layout->LineAdvance + 2.0f * Border};
    layout_element Element = BeginElementRectangle(Layout, &Dim);
    DefaultInteraction(&Element, ItemInteraction);
    EndElement(&Element);
    bool32 IsHot = InteractionsIsHot(Layout->DebugState, ItemInteraction);
    if (BackdropColor.w > 0.0f) {
        PushRect(&DebugState->RenderGroup, &DebugState->BackingTransform, Element.Bounds, 0.0f,
                 BackdropColor);
    }
    TextOutAt({v2{GetMinCorner(Element.Bounds).x + Border,
                  GetMaxCorner(Element.Bounds).y - Border -
                      Layout->DebugState->FontScale *
                          GetStartingBaselineY(Layout->DebugState->DebugFontInfo)}},
              Text, IsHot ? HotColor : ItemColor);
    return Dim;
}

void BeginRow(layout *Layout) {  //
    ++Layout->NoLineFeed;
}

void Label(layout *Layout, const char *Name) {
    debug_interaction NullInteraction = {};
    BasicTextElement(Layout, Name, NullInteraction, V4(1, 1, 1, 1.0f), V4(1, 1, 0, 1));
}

void ActionButton(layout *Layout, const char *Name, debug_interaction Interaction) {
    BasicTextElement(Layout, Name, Interaction, V4(0, 1, 0, 1.0f), V4(1, 1, 0, 1), 4.0f,
                     V4(0, 0, 0, 1.0f));
}
void BooleanButton(layout *Layout, const char *Name, bool32 Highlight,
                   debug_interaction Interaction) {
    BasicTextElement(Layout, Name, Interaction,
                     Highlight ? V4(0.5, 0.5, 0.5, 1) : V4(0, 1, 0, 1.0f), V4(1, 1, 0, 1), 4.0f,
                     V4(0, 0, 0, 1.0f));
}
void EndRow(layout *Layout) {
    Assert(Layout->NoLineFeed > 0);
    --Layout->NoLineFeed;
    AdvanceElement(Layout, RectMinMax(Layout->At, Layout->At));
}

layout BeginLayout(debug_state *DebugState, v2 MouseP, v2 UpperLeftCorner) {
    layout Layout = {};
    Layout.DebugState = DebugState;
    Layout.MouseP = MouseP;
    Layout.BaseCorner = Layout.At = UpperLeftCorner;
    Layout.LineAdvance = DebugState->FontScale * GetLineAdvanceFor(DebugState->DebugFontInfo);
    Layout.SpacingX = 4.0f;
    Layout.SpacingY = 4.0f;
    return Layout;
}

void EndLayout(layout *Layout) {  //
    (void)Layout;
}

real32 GetLineAdvance(debug_state *DebugState) {
    real32 Result = GetLineAdvanceFor(DebugState->DebugFontInfo) * DebugState->FontScale;
    return Result;
}

real32 GetBaseLine(debug_state *DebugState) {
    real32 Result = DebugState->FontScale * GetStartingBaselineY(DebugState->DebugFontInfo);
    return Result;
}

tooltip_buffer AddTooltip(debug_state *DebugState) {
    tooltip_buffer Result;
    Result.Size = sizeof(DebugState->ToolTipText[0]);
    if (DebugState->ToolTipCount < ArrayCount(DebugState->ToolTipText)) {
        Result.Data = DebugState->ToolTipText[DebugState->ToolTipCount++];
    } else {
        Result.Data = DebugState->ToolTipText[DebugState->ToolTipCount - 1];
    }
    return Result;
}

void DrawTooltips(debug_state *DebugState) {
    render_group *RenderGroup = &DebugState->RenderGroup;
    uint32 OldClipRect = RenderGroup->CurrentClipRectIndex;
    RenderGroup->CurrentClipRectIndex = DebugState->DefaultClipRect;
    layout *Layout = &DebugState->MouseTextLayout;

    for (uint32 ToolTipIndex = 0; ToolTipIndex < DebugState->ToolTipCount; ++ToolTipIndex) {
        char *Text = DebugState->ToolTipText[ToolTipIndex];
        rectangle2 TextBounds = DEBUGGetTextSize(DebugState, Text);
        v2 Dim = {GetDim(TextBounds).x, Layout->LineAdvance};
        layout_element Element = BeginElementRectangle(Layout, &Dim);
        EndElement(&Element);
        PushRect(&DebugState->RenderGroup, &DebugState->ToolTipTransform,
                 AddRadiusTo(Element.Bounds, v2{4.0f, 4.0f}), 0.0f, v4{0, 0, 0, 1});
        TextOutAt(V2(GetMinCorner(Element.Bounds).x,
                     GetMaxCorner(Element.Bounds).y -
                         DebugState->FontScale * GetStartingBaselineY(DebugState->DebugFontInfo)),
                  Text, V4(1, 1, 1, 1), 10000.0f);
    }
    RenderGroup->CurrentClipRectIndex = OldClipRect;
}